package com.sz.biz.logistics.core.service.impl;

import com.google.common.collect.Lists;
import com.sz.biz.common.AbstractVersionEntityService;
import com.sz.biz.common.approval.ApprovalService;
import com.sz.biz.common.approval.ApprovalStatus;
import com.sz.biz.common.constants.CommCodes;
import com.sz.biz.common.constants.ErrorCodes;
import com.sz.biz.common.constants.LanguageCode;
import com.sz.biz.common.constants.ModuleNames;
import com.sz.biz.common.customer.dto.CusUserAddressDto;
import com.sz.biz.common.customer.entity.AddressTypeEnum;
import com.sz.biz.common.customer.entity.CusUser;
import com.sz.biz.common.customer.service.CustomerUserAddressService;
import com.sz.biz.common.customer.service.CustomerUserService;
import com.sz.biz.logistics.base.entity.RegionItem;
import com.sz.biz.logistics.base.entity.RegionSchema;
import com.sz.biz.logistics.base.service.RegionItemService;
import com.sz.biz.logistics.base.service.RegionSchemaService;
import com.sz.biz.logistics.base.service.RegionService;
import com.sz.biz.logistics.constants.ProductGroupCode;
import com.sz.biz.logistics.constants.TopServiceTypes;
import com.sz.biz.logistics.core.dto.*;
import com.sz.biz.logistics.core.entity.*;
import com.sz.biz.logistics.core.service.*;
import com.sz.common.base.constants.UserActions;
import com.sz.common.base.dao.ParamData;
import com.sz.common.base.dto.QResultDto;
import com.sz.common.base.dto.QueryParams;
import com.sz.common.base.dto.ResultDto;
import com.sz.common.base.entity.VersionEntityBase;
import com.sz.common.base.exception.CommonErrorCodes;
import com.sz.common.base.exception.Exceptions;
import com.sz.common.base.i18n.I18nMessages;
import com.sz.common.base.utils.CollectionUtils;
import com.sz.common.base.utils.DateUtils;
import com.sz.common.base.utils.EntityUtils;
import com.sz.common.base.utils.StringUtils;
import com.sz.common.core.service.PrincipalLogUtils;
import com.sz.common.core.service.PrincipalUtils;
import com.sz.common.core.system.entity.SysDict;
import com.sz.common.core.system.entity.SysFile;
import com.sz.common.core.system.service.SysDictService;
import com.sz.common.core.system.service.SysFileService;
import com.sz.common.core.system.service.UnitConversionService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Function: ProductServiceImpl. <br>
 * Date: 2017年04月25日 14:30 <br>
 * Author: wentao.chang
 */
@Service
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public class ProductServiceImpl extends AbstractVersionEntityService implements ProductService {

    public static final int PUBLIC = 0;
    @Autowired
    private ServiceService serviceService;
    @Autowired
    private RegionItemService regionItemService;
    @Autowired
    private ServiceRegionRelService serviceRegionRelService;

    @Autowired
    private UnitConversionService unitConversionService;

    @Autowired
    private ProductServiceRelService productServiceRelService;

    @Autowired
    private ApprovalService approvalService;

    @Autowired
    private ProductCargoTypeRelService productCargoTypeRelService;

    @Autowired
    private ProductRegionRelService productRegionRelService;

    @Autowired
    private RegionSchemaService regionSchemaService;

    @Autowired
    private CustomerUserAddressService customerUserAddressService;

    @Autowired
    private ProductGroupService productGroupService;

    @Autowired
    private SysFileService sysFileService;

    @Autowired
    private SysDictService sysDictService;

    @Autowired
    private CustomerUserService customerUserService;

    @Autowired
    private ProductCustomerRelService productCustomerRelService;
    @Autowired
    private ProductServiceRegionRelService productServiceRegionRelService;

    @Autowired
    private ProductServiceCargotypeRelService productServiceCargotypeRelService;
    @Autowired
    private RegionService regionService;

    private static final String SERVICE_TYPE_RECEIVE = "ST001";

    /**
     * 新增主信息
     *
     * @param product 新增主信息
     * @return ProductDto
     */
    @Override
    public ProductDto save(ProductDto product) throws ParseException {
        //产品编码检查
        codeCheck(product.getUid(), product.getCode());
        //检查重量限制
        checkWeightLimit(product);
        //检查预估时效
        checkEstimatedTime(product);
        product.setStatus(1);
        product.setIsVolume(false);
        super.save(product);
        //保存货物类型
        List<ProductCargotypeRelDto> productCargotypeRelDtoList = product.getCargos();
        //保存产品货物类型信息
        updateProductCargotype(productCargotypeRelDtoList, product.getId());
        //保存操作日志
        Map<String, Object> dataBackup = new HashMap<>();
        dataBackup.put("ADD_PRODUCT", product);
        PrincipalLogUtils.addOperationLog(ModuleNames.BIZ, ModuleNames.BIZ_PRODUCT, UserActions.ADD, "产品新增", dataBackup);

        return product;
    }

    /**
     * 检查重量限制
     *
     * @param product product
     */
    private void checkWeightLimit(ProductDto product) {
        BigDecimal weightLimitMin = product.getWeightLimitMin();
        BigDecimal weightLimitMax = product.getWeightLimitMax();
        String weightLimitUnit = product.getWeightLimitUnitCode();
        //下限和上限同时存在，下限小于上限
        if (null != weightLimitMin && null != weightLimitMax) {
            if (weightLimitMax.compareTo(weightLimitMin) < 0) {
                throw Exceptions.bizException(ErrorCodes.ERROR_PRODUCT_WEIGHTLIMIT_MAX_LESS_MIN);
            }
            //默认全部为kg by wentao_chang assign zhuwen
            weightLimitUnit = "kg";
            product.setWeightLimitUnitCode(weightLimitUnit);
        }
        boolean weightUnit = (null != weightLimitMin || null != weightLimitMax) && StringUtils.isEmpty(weightLimitUnit);
        if (weightUnit) {
            throw Exceptions.bizException(ErrorCodes.ERROR_PRODUCT_WEIGHTLIMIT_NO_UNIT);
        }
    }

    /**
     * 检查预估时效
     *
     * @param product product
     */
    private void checkEstimatedTime(ProductDto product) {
        BigDecimal estimatedTime = product.getEstimatedTime();
        String estimatedTimeUnit = product.getEstimatedUnit();
        //预估时效有值，单位不能为空
        if (null != estimatedTime && StringUtils.isEmpty(estimatedTimeUnit)) {
            throw Exceptions.bizException(ErrorCodes.ERROR_PRODUCT_ESTIMATEDTIME_NO_UNIT);
        }
    }

    /**
     * 修改产品基本主信息
     *
     * @param uid     uid
     * @param product 修改主信息
     * @return ProductDto
     */
    @Override
    public ProductDto update(String uid, ProductDto product) throws ParseException {
        Product productExist = findActivedByUid(product.getUid());
        if (null != productExist && !product.getCode().equals(productExist.getCode())) {
            //产品编码检查
            codeCheck(product.getUid(), product.getCode());
        }
        //产品组改变的情况下，对产品范围进行处理
        this.processAddressType(product.getProductGroupLeafId(), productExist.getProductGroupLeafId(), product.getId());

        //检查重量限制
        checkWeightLimit(product);
        //检查预估时效
        checkEstimatedTime(product);
        Product old = findActivedByUid(uid);
        ProductDto productNew = new ProductDto();
        BeanUtils.copyProperties(old, productNew);
        //产品新的信息
        BeanUtils.copyProperties(product, productNew);
        if (ObjectUtils.isEmpty(productNew.getEstimatedTime())) {
            productNew.setEstimatedUnit(null);
        }

        if ((productNew.getWeightLimitMax() == null && productNew.getWeightLimitMin() == null) || productNew.getWeightLimitMax().longValue() <= 0 && productNew.getWeightLimitMin().longValue() <= 0) {
            productNew.setWeightLimitUnitCode(null);
        }


        //修改产品基本信息
        dao.update("ProductMapper.update", productNew);

        //修改产品货物类型
        List<ProductCargotypeRelDto> productCargotypeRelDtoList = product.getCargos();
        //保存产品货物类型信息
        updateProductCargotype(productCargotypeRelDtoList, product.getId());
        //保存操作日志
        Map<String, Object> dataBackup = new HashMap<>();
        dataBackup.put("UPDATE_PRODUCT", product);
        PrincipalLogUtils.addOperationLog(ModuleNames.BIZ, ModuleNames.BIZ_PRODUCT, UserActions.UPDATE, "产品修改", dataBackup);

        return productNew;
    }

    private void processAddressType(Integer leafId, Integer existLeafId, Integer id) {
        if (leafId == null || existLeafId == null || id == null) {
            return;
        }
        //1、获取原来的产品的产品组，与新保存的产品的产品组
        List<ProductGroup> productGroupList = productGroupService.findById(Arrays.asList(leafId, existLeafId));
        Map<Integer, ProductGroup> productGroupMap = new HashMap<>();
        productGroupList.forEach(productGroup -> productGroupMap.put(productGroup.getId(), productGroup));
        ProductGroup productGroup = productGroupMap.get(leafId);
        ProductGroup productGroupExist = productGroupMap.get(existLeafId);
        if (!ObjectUtils.isEmpty(productGroup) && !ObjectUtils.isEmpty(productGroupExist)) {
            //2、判断两个产品组是否一置
            //获取将要保存的产品的父id
            Integer parentId;
            parentId = productGroup.getParentId();
            if (parentId != ProductGroupCode.SEA_TRANSPORT && parentId != ProductGroupCode.AIR_TRANSPORT) {
                parentId = ProductGroupCode.LAND_TRANSPORT;
            }
            //获取已经保存的产品的父id
            Integer parentIdExist;
            parentIdExist = productGroupExist.getParentId();
            if (parentIdExist != ProductGroupCode.SEA_TRANSPORT && parentIdExist != ProductGroupCode.AIR_TRANSPORT) {
                parentIdExist = ProductGroupCode.LAND_TRANSPORT;
            }

            //3、不一置的时候删除旧的产品范围数据
            if (!parentId.equals(parentIdExist)) {
                List<ProductRegionRel> productRegionRels = productRegionRelService.findByProductId(id);
                List<RegionSchema> regionSchemaList = new ArrayList<>();
                productRegionRels.forEach(productRegionRel -> {
                    RegionSchema regionSchema = new RegionSchema();
                    regionSchema.setUid(productRegionRel.getSchemaUid());
                    regionSchema.setIsDeleted(true);
                    regionSchemaList.add(regionSchema);
                });
                //删除产品范围表数据
                productRegionRelService.deleteByProductId(id);
                //删除分区方案数据。
                regionSchemaService.batchDeleteByUids(regionSchemaList);
            }
        }
    }

    /**
     * 保存产品货物类型信息
     *
     * @param productCargotypeRelDtoList productCargotypeRelDtoList
     */
    private void updateProductCargotype(List<ProductCargotypeRelDto> productCargotypeRelDtoList, Integer productId) {
        if (null != productCargotypeRelDtoList && productCargotypeRelDtoList.size() > 0) {
            productCargotypeRelDtoList.forEach(productCargotypeRelDto -> productCargotypeRelDto.setProductId(productId));
            //删除已有货物类型
            productCargoTypeRelService.deleteByProductId(productId);
            //保存货物类型
            List<ProductCargotypeRel> productCargotypeRelList = new ArrayList<ProductCargotypeRel>();
            productCargotypeRelList.addAll(productCargotypeRelDtoList);
            productCargoTypeRelService.batchsave(productCargotypeRelList);
            //保存操作日志
            Map<String, Object> dataBackup = new HashMap<>();
            dataBackup.put("SAVE_PRODUCT_CARGOTYPE_CARGOTYPE_LIST", productCargotypeRelDtoList);
            dataBackup.put("SAVE_PRODUCT_CARGOTYPE_PRODCTID", productId);
            PrincipalLogUtils.addOperationLog(ModuleNames.BIZ, ModuleNames.BIZ_PRODUCT, UserActions.UPDATE, "保存产品货物类型", dataBackup);
        }
    }

    /**
     * 修改产品计重规则
     *
     * @param uid     uid
     * @param product 产品计重规则
     * @return String
     * @throws ParseException ParseException
     */
    @Override
    public String updateWeightInfo(String uid, ProductDto product) throws ParseException {
        Product old = findActivedByUid(uid);
        if (null == old) {
            throw Exceptions.bizException(ErrorCodes.ERROR_MODEL_NOT_FOUND, uid);
        }
        ProductDto productNew = new ProductDto();
        BeanUtils.copyProperties(old, productNew);
        //产品计重新的信息
        productNew.setIsVolume(product.getIsVolume());
        productNew.setVolumeFactor(product.getVolumeFactor());
        productNew.setWeightValueTye(product.getWeightValueTye());

        dao.update("ProductMapper.update", productNew);

        //保存操作日志
        Map<String, Object> dataBackup = new HashMap<>();
        dataBackup.put("SAVE_PRODUCT_CARGOTYPE_CARGOTYPE_LIST", product);
        dataBackup.put("SAVE_PRODUCT_CARGOTYPE_PRODCTUID", uid);
        PrincipalLogUtils.addOperationLog(ModuleNames.BIZ, ModuleNames.BIZ_PRODUCT, UserActions.UPDATE, "修改产品计重规则", dataBackup);

        return uid;
    }


    /**
     * 查询产品下所有的服务
     *
     * @param productUid  productUid
     * @param orderDate   orderDate
     * @param hasDisabled hasDisabled
     * @return List<ProductServiceRelDto>
     */
    @Override
    public List<ProductServiceRel> findServiceDetailsByUidAndDate(String productUid, Date orderDate, boolean hasDisabled) {
        return productServiceRelService.findServiceDetailsByUidAndDate(productUid, orderDate, hasDisabled);
    }

    /**
     * 按类型查询产品下的服务
     *
     * @param productUid       productUid
     * @param type             all：全部服务 main:主服务 required:必选服务 optional:可选服务
     * @param hasDisabled      hasDisabled
     * @param isMainInRequired 必选服务是否包含主服务
     * @return List<ProductServiceRelDto>
     */
    @Override
    public List<ProductServiceRel> findProductServices(String productUid, String type, Integer ordinal, boolean hasDisabled, boolean isMainInRequired) {
        return findProductServicesPrivate(productUid, type, ordinal, hasDisabled, isMainInRequired);
    }

    @Override
    public List<ProductServiceTypeDto> findProductServiceTypes(String productUid, String type) {
        List<ProductServiceRel> dtos = findServiceDetailsByUidAndDate(productUid, new Date(), false);
        List<ProductServiceTypeDto> result = new ArrayList<>();
        switch (type) {
            case "ALL":
                for (ProductServiceRel dto : dtos) {
                    ProductServiceTypeDto serviceTypeDto = new ProductServiceTypeDto(dto.getProductId(), dto.getServiceTypeCode(), dto.getServiceTypeName());
                    if (!result.contains(serviceTypeDto)) {
                        result.add(serviceTypeDto);
                    }
                }
                break;
            case "MAIN":
                for (ProductServiceRel dto : dtos) {
                    String code = dto.getServiceProperty().getCode();
                    if (code.equals(ProductServicePropertyEnum.MAIN.getCode())) {
                        ProductServiceTypeDto serviceTypeDto = new ProductServiceTypeDto(dto.getProductId(), dto.getServiceTypeCode(), dto.getServiceTypeName());
                        if (!result.contains(serviceTypeDto)) {
                            result.add(serviceTypeDto);
                        }
                    }
                }
                break;
            case "REQUIRED":
                for (ProductServiceRel dto : dtos) {
                    String code = dto.getServiceProperty().getCode();
                    if (code.equals(ProductServicePropertyEnum.REQUIRED.getCode())) {
                        ProductServiceTypeDto serviceTypeDto = new ProductServiceTypeDto(dto.getProductId(), dto.getServiceTypeCode(), dto.getServiceTypeName());
                        if (!result.contains(serviceTypeDto)) {
                            result.add(serviceTypeDto);
                        }
                    }
                }
                break;
            case "OPTIONAL":
                for (ProductServiceRel dto : dtos) {
                    dto.setServiceReceive(false);
                    if (SERVICE_TYPE_RECEIVE.equals(dto.getServiceTypeCode())) {
                        dto.setServiceReceive(true);
                    }
                    String code = dto.getServiceProperty().getCode();
                    if (code.equals(ProductServicePropertyEnum.OPTIONAL.getCode())) {
                        ProductServiceTypeDto serviceTypeDto = new ProductServiceTypeDto(dto.getProductId(), dto.getServiceTypeCode(), dto.getServiceTypeName());
                        if (!result.contains(serviceTypeDto)) {
                            result.add(serviceTypeDto);
                        }
                    }
                }
                break;
            default:
                break;
        }
        return result;
    }

    private List<ProductServiceRel> findProductServicesPrivate(String productUid, String type, Integer ordinal, boolean hasDisabled, boolean isMainInRequired) {
        List<ProductServiceRel> dtos = findServiceDetailsByUidAndDate(productUid, new Date(), hasDisabled);
        List<ProductServiceRel> result = new ArrayList<>();
        switch (type) {
            case "ALL":
                result.addAll(dtos);
                break;
            case "MAIN":
                for (ProductServiceRel dto : dtos) {
                    String code = dto.getServiceProperty().getCode();
                    if (code.equals(ProductServicePropertyEnum.MAIN.getCode()) && null == ordinal) {
                        result.add(dto);
                    } else if (code.equals(ProductServicePropertyEnum.MAIN.getCode()) && null != ordinal && ordinal.equals(dto.getOrdinal())) {
                        result.add(dto);
                    }
                }
                break;
            case "REQUIRED":
                for (ProductServiceRel dto : dtos) {
                    String code = dto.getServiceProperty().getCode();
                    if ((code.equals(ProductServicePropertyEnum.REQUIRED.getCode()) || (code.equals(ProductServicePropertyEnum.MAIN.getCode()) && isMainInRequired))
                            && null == ordinal) {
                        result.add(dto);
                    } else if ((code.equals(ProductServicePropertyEnum.REQUIRED.getCode()) || (code.equals(ProductServicePropertyEnum.MAIN.getCode()) && isMainInRequired))
                            && null != ordinal && ordinal.equals(dto.getOrdinal())) {
                        result.add(dto);
                    }
                }
                break;
            case "OPTIONAL":
                for (ProductServiceRel dto : dtos) {
                    dto.setServiceReceive(false);
                    if (SERVICE_TYPE_RECEIVE.equals(dto.getServiceTypeCode())) {
                        dto.setServiceReceive(true);
                    }
                    String code = dto.getServiceProperty().getCode();
                    if (code.equals(ProductServicePropertyEnum.OPTIONAL.getCode()) && null == ordinal) {
                        result.add(dto);
                    } else if (code.equals(ProductServicePropertyEnum.OPTIONAL.getCode()) && null != ordinal && ordinal.equals(dto.getOrdinal())) {
                        result.add(dto);
                    }
                }
                break;
            default:
                break;
        }
        return result;
    }

    @Override
    public ProductServiceRelDto findProductServiceRegions(String uid, String code, Integer ordinal, boolean hasDisabled) {
        List<ProductServiceRel> productServiceRels = findProductServicesPrivate(uid, code, ordinal, hasDisabled, false);
        ProductServiceRelDto productServiceRelDto = null;
        List<ProductServiceRelInfo> productServiceRelInfos = Lists.newArrayList();
        if (null != productServiceRels && !CollectionUtils.isEmpty(productServiceRels)) {
            productServiceRelDto = new ProductServiceRelDto();
            ProductServiceRel productServiceRel = productServiceRels.get(0);
            BeanUtils.copyProperties(productServiceRel, productServiceRelDto);
            for (ProductServiceRel psr : productServiceRels) {
                ProductServiceRelInfo productServiceRelInfo = new ProductServiceRelInfo();
                BeanUtils.copyProperties(psr, productServiceRelInfo);
                //产品服务范围-起始
                List<ProductServiceRelRegionInfo> regionsStart = productServiceRegionRelService.findByPsId(psr.getId(), CommCodes.PRODUCT_SERVICE_REGION_START);
                if (null != regionsStart && !CollectionUtils.isEmpty(regionsStart)) {
                    productServiceRelInfo.setRegionsStart(regionsStart);
                }
                //产品服务范围-终点
                List<ProductServiceRelRegionInfo> regionsEnd = productServiceRegionRelService.findByPsId(psr.getId(), CommCodes.PRODUCT_SERVICE_REGION_END);
                if (null != regionsEnd && !CollectionUtils.isEmpty(regionsEnd)) {
                    productServiceRelInfo.setRegionsEnd(regionsEnd);
                }
                //产品服务货物类型
                List<ProductServiceRelCargotypeInfo> cargotypeInfos = productServiceCargotypeRelService.findByPsId(psr.getId());
                if (null != cargotypeInfos && !CollectionUtils.isEmpty(cargotypeInfos)) {
                    productServiceRelInfo.setCargos(cargotypeInfos);
                }
                productServiceRelInfos.add(productServiceRelInfo);
            }
            if (!CollectionUtils.isEmpty(productServiceRelInfos)) {
                productServiceRelDto.setProductServiceRelInfos(productServiceRelInfos);
            }
        }
        return productServiceRelDto;
    }

    /**
     * 根据uid启用产品
     *
     * @param uid uid
     */
    @Override
    public Integer online(String uid) throws ParseException {
        ProductDto productDto = findActivedByUid(uid);
        //提交流程
        ApprovalStatus fromStatus;
        if (ObjectUtils.isEmpty(productDto)) {
            throw Exceptions.bizException(ErrorCodes.ERROR_PRODUCT_NOT_EXIST);
        }

        //判断分区是不为空
        this.judgeRegion(productDto);

        if (productDto.getIsOnline() == null) {
            fromStatus = ApprovalStatus.Approved;
        } else {
            fromStatus = ApprovalStatus.Offline;
        }
        //检查服务的在线情况
        List<String> serviceUids = productServiceRelService.checkMainRequiredService(productDto.getId(), null);
        if (!CollectionUtils.isEmpty(serviceUids)) {
            List<com.sz.biz.logistics.core.entity.Service> serviceList = serviceService.findActivedByUids(serviceUids);
            if (!CollectionUtils.isEmpty(serviceList)) {
                for (com.sz.biz.logistics.core.entity.Service serviceDto : serviceList) {
                    if (serviceDto.getStatus().compareTo(3) != 0 || null == serviceDto.getIsOnline() || !serviceDto.getIsOnline()) {
                        throw Exceptions.bizException(ErrorCodes.ERROR_PRODUCT_ONLINE_MAIN_SERVICE_ONLINECHECK);
                    }
                }
            } else {
                throw Exceptions.bizException(ErrorCodes.ERROR_PRODUCT_ONLINE_MAIN_SERVICE_ONLINECHECK);
            }
        } else {
            throw Exceptions.bizException(ErrorCodes.ERROR_PRODUCT_ONLINE_MAIN_SERVICE_ONLINECHECK);
        }
        return handlerOnLineState(uid, true, fromStatus, ApprovalStatus.Online);
    }

    /**
     * 根据uid停用产品
     *
     * @param uid uid
     */
    @Override
    public Integer offline(String uid) throws ParseException {
        return handlerOnLineState(uid, false, ApprovalStatus.Online, ApprovalStatus.Offline);
    }

    /**
     * 根据uids删除实体
     *
     * @param uids uid集合
     */
    @Override
    public void batchdelete(List<String> uids) {
        if (CollectionUtils.isEmpty(uids)) {
            return;
        }
        Map<String, Object> map = new HashMap<>();
        map.put("array", uids);
        List<Product> products = dao.findForList("ProductMapper.findActivedByUids", map, Product.class);
        List<String> uidssaved = products.stream()
                .filter(product -> product.getStatus().compareTo(1) == 0)
                .map(VersionEntityBase::getUid)
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(uidssaved)) {
            throw Exceptions.bizException(CommonErrorCodes.ERROR_MODEL_NOT_SAVED);
        }
        Map<String, Object> param = new HashMap<>();
        param.put("lastUpdateUserId", PrincipalUtils.getAccountId());
        param.put("array", uids);
        param.put("inactiveTime", dao.getDbDate());
        dao.update("ProductMapper.deleteByUidsStep1", param);
        dao.update("ProductMapper.deleteByUidsStep2", param);
        //保存操作日志
        Map<String, Object> dataBackup = new HashMap<>();
        dataBackup.put("DELETE_PRODUCT", uids);
        PrincipalLogUtils.addOperationLog(ModuleNames.BIZ, ModuleNames.BIZ_PRODUCT, UserActions.DELETE, "删除产品", dataBackup);
    }

    /**
     * 根据uid删除实体
     *
     * @param uid  uid
     * @param date date
     */
    @Override
    public String delete(String uid, Date date) {
        Product product = (Product) dao.findForObject("ProductMapper.findActivedByUid", uid);
        checkQueryDataValid(uid, product);
        Map<String, Object> param = new HashMap<>();
        param.put("lastUpdateUserId", PrincipalUtils.getAccountId());
        param.put("uid", uid);
        param.put("inactiveTime", date == null ? dao.getDbDate() : date);
        dao.update("ProductMapper.deleteByUidStep1", param);
        dao.update("ProductMapper.deleteByUidStep2", param);
        //保存操作日志
        Map<String, Object> dataBackup = new HashMap<>();
        dataBackup.put("DELETE_PRODUCT", product);
        PrincipalLogUtils.addOperationLog(ModuleNames.BIZ, ModuleNames.BIZ_PRODUCT, UserActions.DELETE, "删除产品", dataBackup);
        return uid;
    }

    private void checkQueryDataValid(Object key, Product product) {
        if (product == null) {
            throw Exceptions.bizException(ErrorCodes.ERROR_MODEL_NOT_FOUND, key);
        }
    }

    @Override
    public List<Product> findActivedByUids(List<String> uids) {
        List<Product> productList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(uids)) {
            ParamData pd = new ParamData();
            pd.put("array", uids);
            productList = dao.findForList("ProductMapper.findActivedByUids", pd, Product.class);
        }
        return productList;
    }

    @Override
    public List<Product> findShortActivedByUids(List<String> uids) {
        List<Product> productList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(uids)) {
            ParamData pd = new ParamData();
            pd.put("array", uids);
            productList = dao.findForList("ProductMapper.findShortActivedByUids", pd, Product.class);
        }
        return productList;
    }

    @Override
    public Product findShortActivedByUid(String uid) {
        Product product = null;
        List<Product> productList = this.findShortActivedByUids(Arrays.asList(uid));
        if (!CollectionUtils.isEmpty(productList)) {
            product = productList.get(0);
        }
        return product;
    }

    @Override
    public List<Product> findShortActivedByIds(List<Integer> ids) {
        List<Product> productList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(ids)) {
            ParamData pd = new ParamData();
            pd.put("ids", ids);
            productList = dao.findForList("ProductMapper.findShortActivedByIds", pd, Product.class);
        }
        return productList;
    }

    @Override
    public Product findShortActivedById(Integer id) {
        Product product = null;
        List<Product> productList = this.findShortActivedByIds(Arrays.asList(id));
        if (!CollectionUtils.isEmpty(productList)) {
            product = productList.get(0);
        }
        return product;
    }

    /**
     * 根据uid查询可用生效的实体
     *
     * @param uid uid
     * @return 查询出来的实体对象
     */
    @Override
    public ProductDto findActivedByUid(String uid) {

        Product product = (Product) dao.findForObject("ProductMapper.findActivedByUid", uid);
        if (product == null) {
            return null;
        }
        ProductDto dto = new ProductDto();
        BeanUtils.copyProperties(product, dto);

        List<ProductServiceRel> productServiceRels = productServiceRelService.findByProductId(product.getId());
        if (!CollectionUtils.isEmpty(productServiceRels)) {
            List<String> serviceUids = EntityUtils.getStringPropListFromBeans(productServiceRels, "serviceUid");
            List<com.sz.biz.logistics.core.entity.Service> services = serviceService.findActivedByUids(serviceUids);
            Map<String, com.sz.biz.logistics.core.entity.Service> serviceMap = EntityUtils.getStringKeyMapFromBeans(services, "uid");
            for (ProductServiceRel rel : productServiceRels) {
                ProductServiceRel relDto = new ProductServiceRel();
                BeanUtils.copyProperties(rel, relDto);
                if (rel.getServiceUid() != null && serviceMap.get(rel.getServiceUid()) != null) {
                    relDto.setServiceName(serviceMap.get(rel.getServiceUid()).getName());
                }
                dto.getServices().add(relDto);
            }
        }

        dto.setStatusName(super.getStatusName(dto.getStatus(), dto.getIsOnline()));

        return dto;
    }

    /**
     * 根据主键Id查询单个实体
     *
     * @param id 主键id
     * @return 查询出来的实体对象
     */
    @Override
    public ProductDto findById(Integer id) {
        Product product = (Product) dao.findForObject("ProductMapper.findById", id);
        if (product == null) {
            return null;
        }
        ProductDto dto = new ProductDto();
        BeanUtils.copyProperties(product, dto);
        List<ProductCargotypeRelDto> cargoTypeList = productCargoTypeRelService.findByProductId(product.getId());
        Boolean isMainExist = false;
        ProductServiceRel productServiceRel = productServiceRelService.checkMainService(product.getId());
        if (productServiceRel != null) {
            isMainExist = true;
        }
        dto.setCargos(cargoTypeList);
        dto.setIsMainExist(isMainExist);
        return dto;
    }

    /**
     * 产品是否自动受理, true: 自动受理； false： 人工受理
     *
     * @param uid
     * @return
     */
    @Override
    public boolean isAcceptAuto(String uid) {
        Product product = (Product) dao.findForObject("ProductMapper.findActivedByUid", uid);
        if (null != product && product.getAcceptType().compareTo(0) == 0) {
            return true;
        }
        return false;
    }

    /**
     * 根据uid查询产品
     *
     * @param uid
     * @return
     */
    @Override
    public ProductDto findByUid(String uid) {
        Product product = (Product) dao.findForObject("ProductMapper.findActivedByUid", uid);
        if (product == null) {
            return null;
        }
        ProductDto dto = new ProductDto();
        BeanUtils.copyProperties(product, dto);
        List<ProductCargotypeRelDto> cargoTypeList = productCargoTypeRelService.findByProductId(product.getId());
        Boolean isMainExist = false;
        ProductServiceRel productServiceRel = productServiceRelService.checkMainService(product.getId());
        if (productServiceRel != null) {
            isMainExist = true;
        }
        dto.setCargos(cargoTypeList);
        dto.setIsMainExist(isMainExist);
        return dto;
    }

    /**
     * 根据主键Id查询单个实体-客户平台
     *
     * @param id 主键id
     * @return 查询出来的实体对象
     */
    @Override
    public ProductCustomerDto findByIdCustomer(Integer id) {
        Product product = (Product) dao.findForObject("ProductMapper.findById", id);
        if (product == null) {
            return null;
        }
        String image = product.getImage();
        if (StringUtils.isEmpty(image)) {
            //所有产品组
            List<ProductGroup> productGroups = productGroupService.list();
            //获取产品组图片
            image = getProductGroupImage(product.getProductGroupLeafId(), productGroups);
        }
        SysFile sysFile = sysFileService.getFileInfo(image);
        if (null != sysFile) {
            product.setImage(sysFile.getFileLocation());
        }
        String unitName = sysDictService.getNameByCode("biz.product.estimated.unit", product.getEstimatedUnit());
        product.setEstimatedUnit(unitName);
        ProductCustomerDto dto = new ProductCustomerDto();
        BeanUtils.copyProperties(product, dto);
        List<ProductCargotypeRelDto> cargoTypeList = productCargoTypeRelService.findByProductId(product.getId());
        List<ProductServiceTypeDto> optionalServices = productServiceRelService.findByProductIdAndServiceProperty(product.getId(), ProductServicePropertyEnum.OPTIONAL);
        dto.setCargos(cargoTypeList);
        dto.setOptionalServiceTypes(optionalServices);
        return dto;
    }

    @Override
    public Boolean checkMainService(Integer id) {
        Boolean isMainExist = false;
        ProductServiceRel productServiceRel = productServiceRelService.checkMainService(id);
        if (productServiceRel != null) {
            isMainExist = true;
        }
        return isMainExist;
    }

    @Override
    public List<Integer> findIds(Integer id) {
        ParamData paramData = new ParamData();
        paramData.put("id", id);
        return dao.findForList(getSqlName("findIds"), paramData, Integer.class);
    }

    /**
     * 产品列表初始化，返回产品id, uid,名称
     *
     * @param params
     * @return
     */
    @Override
    public ResultDto findProductListReturnUidName(QueryParams params) {
        ParamData pd = this.convertQueryParams(params);
        //获取产品基本信息
        List<Product> products = dao.findForList("ProductMapper.findListPageShort", pd, Product.class);
        List<Map<String, Object>> sDtos = populateProductShort(products);
        return new QResultDto(sDtos, pd.getPagination());
    }

    /**
     * 产品列表初始化，返回产品id, uid,名称,没有分页
     *
     * @param params
     * @return
     */
    @Override
    public List<Map<String, Object>> findProductListReturnUidNameAll(QueryParams params) {
        ParamData pd = this.convertQueryParams(params);
        //获取产品基本信息
        List<Product> products = dao.findForList("ProductMapper.findListShort", pd, Product.class);
        List<Map<String, Object>> sDtos = populateProductShort(products);
        return sDtos;
    }

    /**
     * 返回产品组信息
     *
     * @param id
     * @return
     */
    @Override
    public ProductGroupInfo getProductGroupById(Integer id) {
        return (ProductGroupInfo) dao.findForObject(getSqlName("getProductGroupById"), id);
    }

    /**
     * 返回产品所在组配置的货币类型
     *
     * @param productUid
     * @return
     */
    @Override
    public String getProductCurrencyByUid(String productUid) {
        return (String) dao.findForObject(getSqlName("getProductCurrencyByUid"), productUid);
    }

    /**
     * 返回所有私有产品的产品组
     *
     * @return
     */
    @Override
    public List<Integer> privateProductGroups() {
        return dao.findForList(getSqlName("privateProductGroups"), null, Integer.class);
    }

    /**
     * 组装返回的产品短接口数据
     *
     * @param products
     * @return
     */
    private List<Map<String, Object>> populateProductShort(List<Product> products) {
        List<Map<String, Object>> sDtos = new ArrayList<>();
        if (!CollectionUtils.isEmpty(products)) {
            for (Product product : products) {
                Map<String, Object> dto = new HashMap<>();
                dto.put("id", product.getId());
                dto.put("uid", product.getUid());
                dto.put("name", product.getName());
                dto.put("code", product.getCode());
                sDtos.add(dto);
            }
        }
        return sDtos;
    }

    @Override
    public List<Map> findServicesById(Integer productId) {
        return productServiceRelService.findServicesByProductId(productId);
    }

    /**
     * 根据uid查询可用生效的实体
     *
     * @param uid  uid
     * @param time 时间点
     * @return 查询出来的实体对象
     */
    @Override
    public ProductDto findByUidAndTime(String uid, Date time) {
        Map<String, String> map = new HashMap<>();
        map.put("uid", uid);
        map.put("time", DateUtils.formatDetailDate(time));
        Product product = (Product) dao.findForObject("ProductMapper.findByUidAndTime", map);
        if (product == null) {
            return null;
        }
        ProductDto dto = new ProductDto();
        BeanUtils.copyProperties(product, dto);
        return dto;
    }

    /**
     * 异步校验产品名称
     *
     * @param uid
     * @param name
     * @return
     */
    @Override
    public void nameCheck(String uid, String name) {
        Map<String, Object> map = new HashMap<>();
        map.put("uid", uid);
        map.put("name", name);
        List<Product> listName = dao.findForList("ProductMapper.findByName", map, Product.class);
        if (listName.size() > 0) {
            throw Exceptions.bizException(ErrorCodes.ERROR_MODEL_NAME_EXIST, name);
        }
    }

    /**
     * 校验产品编码唯一性
     *
     * @param uid
     * @param code
     */
    @Override
    public void codeCheck(String uid, String code) {
        Map<String, Object> map = new HashMap<>();
        map.put("uid", uid);
        map.put("code", code);
        List<Product> productList = dao.findForList("ProductMapper.findByCode", map, Product.class);
        if (null != productList && productList.size() > 0) {
            throw Exceptions.bizException(ErrorCodes.ERROR_PRODUCT_CODE_EXIST, code);
        }
    }

    /**
     * 根据条件查询实体
     *
     * @param params 查询的参数集
     * @return 查询出的数据
     */
    @Override
    public QResultDto findByFilter(QueryParams params) {
        ParamData pd = this.convertQueryParams(params);
        List<Product> products = dao.findForList("ProductMapper.findByFilterListPage", pd, Product.class);
        List<ProductDto> sDtos = new ArrayList<>();
        for (Product product : products) {
            ProductDto dto = new ProductDto();
            BeanUtils.copyProperties(product, dto);
            dto.setStatusName(super.getStatusName(product.getStatus(), dto.getIsOnline()));
            List<ProductCargotypeRelDto> cargoTypeList = productCargoTypeRelService.findByProductId(product.getId());
            dto.setCargos(cargoTypeList);
            sDtos.add(dto);
        }
        return new QResultDto(sDtos, pd.getPagination());
    }

    /**
     * 根据条件查询实体-客户系统
     *
     * @param params 查询的参数集
     * @return 查询出的数据
     */
    @Override
    public QResultDto findByFilterCustomer(QueryParams params) {
        ParamData pd = this.convertQueryParams(params);
        //获取当前登录用户
        CusUser user = customerUserService.findById(PrincipalUtils.getAccountId());
        Integer customerId = -1;
        if (null != user) {
            customerId = user.getRefCustomerId();
        }
        //根据客户帐号获取客户产品可见性信息
        pd = populateCustomerProduct(customerId, pd);
        List<Product> products = dao.findForList("ProductMapper.findByFilterCustomerListPage", pd, Product.class);
        return populateProductListCustomer(products, pd);
    }

    /**
     * 客户平台产品列表
     *
     * @param products
     * @return
     */
    private QResultDto populateProductListCustomer(List<Product> products, ParamData pd) {
        //所有产品组
        List<ProductGroup> productGroups = productGroupService.list();
        //所有产品的图片
        List<SysFile> sysFiles = sysFileService.allProductFiles();

        List<Integer> productIds = Lists.newArrayList();

        List<ProductCustomerDto> sDtos = new ArrayList<>();
        for (Product product : products) {
            productIds.add(product.getId());
        }
        //所有货物类型
        List<ProductCargotypeRelDto> cargoTypeList = productCargoTypeRelService.findByProductIds(productIds);
        List<ProductServiceTypeDto> optionalServiceTypes = productServiceRelService.findByProductIdsAndServiceProperty(productIds, ProductServicePropertyEnum.OPTIONAL);
        for (Product product : products) {
            //如果产品图片没有，从产品组获取对应图片
            String image = product.getImage();
            if (StringUtils.isEmpty(image)) {
                //获取产品组图片
                image = getProductGroupImage(product.getProductGroupLeafId(), productGroups);
            }
            String imageLocation = getProductImageLocation(image, sysFiles);
            if (!StringUtils.isEmpty(imageLocation)) {
                product.setImage(imageLocation);
            }
            ProductCustomerDto dto = new ProductCustomerDto();
            BeanUtils.copyProperties(product, dto);
            List<ProductCargotypeRelDto> cargos = Lists.newArrayList();
            List<ProductServiceTypeDto> services = Lists.newArrayList();
            //匹配货物类型
            if (!CollectionUtils.isEmpty(cargoTypeList)) {
                for (ProductCargotypeRelDto cargo : cargoTypeList) {
                    if (cargo.getProductId().compareTo(product.getId()) == 0) {
                        cargos.add(cargo);
                    }
                }
            }
            dto.setCargos(cargos);
            if (!CollectionUtils.isEmpty(optionalServiceTypes)) {
                for (ProductServiceTypeDto service : optionalServiceTypes) {
                    if (service.getProductId().compareTo(product.getId()) == 0) {
                        services.add(service);
                    }
                }
            }
            dto.setOptionalServiceTypes(services);
            sDtos.add(dto);
        }
        return new QResultDto(sDtos, pd.getPagination());
    }

    /**
     * 产品图片
     *
     * @param fileId
     * @param sysFiles
     * @return
     */
    private String getProductImageLocation(String fileId, List<SysFile> sysFiles) {
        if (!CollectionUtils.isEmpty(sysFiles)) {
            for (SysFile sysFile : sysFiles) {
                if (sysFile.getFileId().equals(fileId)) {
                    return sysFile.getFileLocation();
                }
            }
        }
        return null;
    }

    /**
     * 产品组图片
     *
     * @param leafId
     * @param productGroups
     * @return
     */
    private String getProductGroupImage(Integer leafId, List<ProductGroup> productGroups) {
        String groupImage = "";
        ProductGroup productGroup = isProductGroupImage(leafId, productGroups);
        if (null != productGroup) {
            if (!StringUtils.isEmpty(productGroup.getImage())) {
                groupImage = productGroup.getImage();
            } else {
                if (null != productGroup.getParentId() && productGroup.getParentId() != 0) {
                    groupImage = getProductGroupImage(productGroup.getParentId(), productGroups);
                }
            }

        }
        return groupImage;
    }

    /**
     * 产品组图片
     *
     * @param groupId
     * @param productGroups
     * @return
     */
    private ProductGroup isProductGroupImage(Integer groupId, List<ProductGroup> productGroups) {
        if (!CollectionUtils.isEmpty(productGroups)) {
            for (ProductGroup productGroup : productGroups) {
                if (groupId.compareTo(productGroup.getId()) == 0) {
                    return productGroup;
                }
            }
        }
        return null;
    }

    /**
     * 客户可见产品
     *
     * @param customerId
     * @param pd
     * @return
     */
    @Override
    public ParamData populateCustomerProduct(Integer customerId, ParamData pd) {
        //客户可见产品及产品组列表
        List<ProductCustomerRel> productCustomerRelList = productCustomerRelService.findByCustomerId(customerId, null);
        //白名单
        pd = populateCustomerProductWhite(pd, productCustomerRelList);
        //黑名单
        pd = populateCustomerProductBlack(pd, productCustomerRelList);

        return pd;
    }

    @Override
    public List<Product> findProductInfoByNameOrCode(String nameOrCode, Integer customerId) {
        ParamData pd = new ParamData();
        pd.put("customerId",customerId);
        pd.put("q", nameOrCode);
        pd = populateCustomerProduct(customerId, pd);
        //获取产品基本信息
        return  dao.findForList("ProductMapper.findProductInfoByNameOrCode", pd, Product.class);
    }

    @Override
    public List<Product> findProductInfoByNameOrCodeList(List<String>  nameOrCodes, Integer customerId) {
        ParamData pd = new ParamData();
        pd.put("customerId",customerId);
        pd.put("nameOrCodes", nameOrCodes);
        pd = populateCustomerProduct(customerId, pd);
        //获取产品基本信息
        return  dao.findForList("ProductMapper.findProductInfoByNameOrCodeList", pd, Product.class);
    }

    /**
     * 客户可见产品-黑名单
     *
     * @param pd
     * @param productCustomerRels
     * @return
     */
    private ParamData populateCustomerProductBlack(ParamData pd, List<ProductCustomerRel> productCustomerRels) {
        //黑名单
        List<Integer> bProductGroupIds = Lists.newArrayList();
        List<String> bProductUids = Lists.newArrayList();
        //根据客户帐号获取客户产品可见性信息
        List<ProductCustomerRel> productCustomerRelListBlack = getCustomerProductShow(productCustomerRels, true);
        if (!CollectionUtils.isEmpty(productCustomerRelListBlack)) {
            //白黑名单标志 0:可以看到公共产品和自己设置的白名单产品 1: 白名单(只能看白名单里的产品)； 2： 黑名单(不能看的产品)
            for (ProductCustomerRel productCustomerRel : productCustomerRelListBlack) {
                //type 0: 产品组； 1： 产品
                if (productCustomerRel.getType().compareTo(0) == 0 && null != productCustomerRel.getProductGroupId()) {
                    bProductGroupIds.add(productCustomerRel.getProductGroupId());
                } else if (productCustomerRel.getType().compareTo(1) == 0 && !StringUtils.isEmpty(productCustomerRel.getProductUid())) {
                    bProductUids.add(productCustomerRel.getProductUid());
                }
            }
        }
        pd.put("bProductGroupIds", bProductGroupIds);
        pd.put("bProductUids", bProductUids);

        return pd;
    }

    /**
     * 客户可见产品-白名单
     *
     * @param pd
     * @param productCustomerRels
     * @return
     */
    private ParamData populateCustomerProductWhite(ParamData pd, List<ProductCustomerRel> productCustomerRels) {
        //白名单
        List<Integer> productGroupIds = Lists.newArrayList();
        List<String> productUids = Lists.newArrayList();
        Integer wbFlag = 0;
        //根据客户帐号获取客户产品可见性信息
        List<ProductCustomerRel> productCustomerRelListWhite = getCustomerProductShow(productCustomerRels, false);
        if (!CollectionUtils.isEmpty(productCustomerRelListWhite)) {
            //白黑名单标志 0:可以看到公共产品和自己设置的白名单产品 1: 白名单(只能看白名单里的产品)； 2： 黑名单(不能看的产品)
            for (ProductCustomerRel productCustomerRel : productCustomerRelListWhite) {
                //type 0: 产品组； 1： 产品
                wbFlag = productCustomerRel.getWbFlag();
                if (productCustomerRel.getType().compareTo(0) == 0 && null != productCustomerRel.getProductGroupId()) {
                    productGroupIds.add(productCustomerRel.getProductGroupId());
                } else if (productCustomerRel.getType().compareTo(1) == 0 && !StringUtils.isEmpty(productCustomerRel.getProductUid())) {
                    productUids.add(productCustomerRel.getProductUid());
                }
            }
        }
        //根据客户帐号获取客户产品可见性信息
        if (CollectionUtils.isEmpty(productGroupIds)) {
            productGroupIds.add(-1);
        }
        if (CollectionUtils.isEmpty(productUids)) {
            productUids.add("");
        }
        pd.put("productGroupIds", productGroupIds);
        pd.put("productUids", productUids);
        pd.put("wbFlag", wbFlag);

        return pd;
    }

    /**
     * 客户产品白名单和黑名单
     *
     * @param productCustomerRelList
     * @param ibBlack
     */
    private List<ProductCustomerRel> getCustomerProductShow(List<ProductCustomerRel> productCustomerRelList, Boolean ibBlack) {
        List<ProductCustomerRel> productCustomerRels = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(productCustomerRelList)) {
            for (ProductCustomerRel productCustomerRel : productCustomerRelList) {
                if (ibBlack && productCustomerRel.getWbFlag().compareTo(2) == 0) {
                    productCustomerRels.add(productCustomerRel);
                } else if (!ibBlack && productCustomerRel.getWbFlag().compareTo(2) != 0) {
                    productCustomerRels.add(productCustomerRel);
                }
            }
        }
        return productCustomerRels;
    }

    /**
     * 订单产品初始化
     *
     * @param params 查询的参数集
     * @return 查询出的数据
     */
    @Override
    public QResultDto findByFilterForOrder(QueryParams params) {
        ParamData pd = this.convertQueryParams(params);
        Integer customerId = (Integer) pd.get("customerId");
        pd = populateCustomerProduct(customerId, pd);
        //获取产品基本信息
        List<Product> products = dao.findForList("ProductMapper.findByFilterForOrderListPage", pd, Product.class);
        List<Map<String, Object>> sDtos = new ArrayList<>();
        for (Product product : products) {
            Map<String, Object> dto = new HashMap<>(16);
            dto.put("id", product.getId());
            dto.put("uid", product.getUid());
            dto.put("code", product.getCode());
            dto.put("name", product.getName());
            dto.put("productGroupRootId", product.getProductGroupRootId());
            dto.put("productGroupId", product.getProductGroupLeafId());
            //获取产品货物类型数据
            List<ProductCargotypeRelDto> cargoTypeList = productCargoTypeRelService.findByProductIdForOrder(product.getId());
            dto.put("cargos", cargoTypeList);
            //获取产品下可选服务
            List<ProductServiceTypeDto> serviceTypeDtos = productServiceRelService.findByProductIdAndServiceProperty(product.getId(), ProductServicePropertyEnum.OPTIONAL);
            dto.put("services", serviceTypeDtos);
            sDtos.add(dto);
        }

        return new QResultDto(sDtos, pd.getPagination());
    }

    /**
     * 提交产品
     *
     * @param uids
     */
    @Override
    public void submit(List<String> uids) throws ParseException {
        if (CollectionUtils.isEmpty(uids)) {
            return;
        }
        //产品是否有启用的主服务
        checkOnlineMainService(uids);

        Map<String, Object> map = new HashMap<>();
        map.put("array", uids);
        List<Product> products = dao.findForList("ProductMapper.findActivedByUids", map, Product.class);
        List<String> uidssaved = new ArrayList<>();
        for (Product product : products) {
            if (product.getStatus().compareTo(1) == 0) {
                this.judgeRegion(product);
                uidssaved.add(product.getUid());
                //提交流程
                approvalService.approval(ApprovalService.ENTITY_TYPE_PRODUCT, product.getUid(), ApprovalStatus.Draft, ApprovalStatus.Submitted, "", PrincipalUtils.getAccountId());
            }
        }
        if (CollectionUtils.isEmpty(uidssaved)) {
            return;
        }
        map = new HashMap<>();
        map.put("status", 2);
        map.put("uids", uidssaved);
        map.put("lastUpdateUserId", PrincipalUtils.getAccountId());
        map.put("isRejected", false);
        dao.update("ProductMapper.updateStatus", map);

        //保存操作日志
        Map<String, Object> dataBackup = new HashMap<>();
        dataBackup.put("SUBMIT_PRODUCT", uids);
        PrincipalLogUtils.addOperationLog(ModuleNames.BIZ, ModuleNames.BIZ_PRODUCT, UserActions.COMMIT, "提交产品", dataBackup);

    }

    private void judgeRegion(Product product) {
        List<ProductRegionRel> regionRelList = productRegionRelService.findByProductId(product.getId());
        if (!CollectionUtils.isEmpty(regionRelList)) {
            for (ProductRegionRel productRegionRel : regionRelList) {
                RegionSchema regionSchema = regionSchemaService.findEntryActivedByUid(productRegionRel.getSchemaUid());
                if (!ObjectUtils.isEmpty(regionSchema) && StringUtils.isEmpty(regionSchema.getItemDetail())) {
                    throw Exceptions.bizException(ErrorCodes.ERROR_PRODUCT_ONLINE_REGION_CHECK);
                }
            }
        }
    }

    /**
     * 验证产品是否存在已启用的主服务
     *
     * @param uids
     */
    private void checkOnlineMainService(List<String> uids) {
        Map<String, Object> map = new HashMap<>();
        map.put("array", uids);
        List<Product> products = dao.findForList("ProductMapper.findActivedByUids", map, Product.class);
        if (null != products) {
            for (Product product : products) {
                ProductServiceRel productServiceRel = productServiceRelService.checkMainService(product.getId());
                if (null == productServiceRel) {
                    throw Exceptions.bizException(ErrorCodes.ERROR_PRODUCT_ONLINE_MAIN_SERVICE_CHECK);
                }
            }
        }
    }

    /**
     * 审核产品
     *
     * @param uid
     */
    @Override
    public void audit(String uid, String msg) throws ParseException {
        List<String> uids = new ArrayList<String>();
        uids.add(uid);
        if (CollectionUtils.isEmpty(uids)) {
            return;
        }
        Map<String, Object> map = new HashMap<>();
        map.put("array", uids);
        List<Product> products = dao.findForList("ProductMapper.findActivedByUids", map, Product.class);
        List<String> uidssaved = new ArrayList<>();
        for (Product product : products) {
            if (product.getStatus().compareTo(2) == 0) {
                uidssaved.add(product.getUid());
                //审核日志
                approvalService.approval(ApprovalService.ENTITY_TYPE_PRODUCT, product.getUid(), ApprovalStatus.Submitted, ApprovalStatus.Approved, msg, PrincipalUtils.getAccountId());
            }
        }
        if (CollectionUtils.isEmpty(uidssaved)) {
            return;
        }

        map = new HashMap<>();
        map.put("status", 3);
        map.put("uids", uidssaved);
        map.put("lastUpdateUserId", PrincipalUtils.getAccountId());
        map.put("isRejected", false);
        dao.update("ProductMapper.updateStatus", map);
        //保存操作日志
        Map<String, Object> dataBackup = new HashMap<>();
        dataBackup.put("UPDATE_PRODUCT", map);
        PrincipalLogUtils.addOperationLog(ModuleNames.BIZ, ModuleNames.BIZ_PRODUCT, UserActions.APPROVE, "产品审核通过", dataBackup);
    }

    /**
     * 打回产品
     *
     * @param productUid
     */
    @Override
    public void reject(String productUid, String msg) {
        List<String> uids = new ArrayList<String>();
        uids.add(productUid);
        List<String> uidsSaved = new ArrayList<>();
        for (String uid : uids) {
            Product product = (Product) dao.findForObject("ProductMapper.findActivedByUid", uid);
            if (product.getStatus().compareTo(2) == 0) {
                uidsSaved.add(uid);
                //审核日志
                approvalService.approval(ApprovalService.ENTITY_TYPE_PRODUCT, uid, ApprovalStatus.Submitted, ApprovalStatus.Draft, msg, PrincipalUtils.getAccountId());
            }
        }
        if (CollectionUtils.isEmpty(uidsSaved)) {
            return;
        }
        Map<String, Object> map = new HashMap<>();
        map.put("status", 1);
        map.put("uids", uidsSaved);
        map.put("isRejected", true);
        map.put("lastUpdateUserId", PrincipalUtils.getAccountId());
        dao.update("ProductMapper.updateStatus", map);
        //保存操作日志
        Map<String, Object> dataBackup = new HashMap<>();
        dataBackup.put("UPDATE_PRODUCT", map);
        PrincipalLogUtils.addOperationLog(ModuleNames.BIZ, ModuleNames.BIZ_PRODUCT, UserActions.UPDATE, "打回产品", dataBackup);
    }

    /**
     * 查询产品下的服务
     *
     * @param productUid
     * @param orderDate
     * @return
     */
    @Override
    public List<ProductServiceRel> findServicesByUidAndDate(String productUid, Date orderDate) {
        return productServiceRelService.findServicesByUidAndDate(productUid, orderDate);
    }


    /**
     * 修改产品上下线状态
     *
     * @param uid
     * @param isOnline
     * @throws ParseException
     */
    private Integer handlerOnLineState(String uid, boolean isOnline, ApprovalStatus fromStatus, ApprovalStatus toStatus) throws ParseException {
        Map<String, Object> map = new HashMap<>();
        map.put("uid", uid);
        map.put("isOnline", isOnline);
        map.put("isActive", true);
        map.put("lastUpdateUserId", PrincipalUtils.getAccountId());
        dao.update("ProductMapper.updateOnline", map);
        //审核日志
        approvalService.approval(ApprovalService.ENTITY_TYPE_PRODUCT, uid, fromStatus, toStatus, "", PrincipalUtils.getAccountId());
        //保存操作日志
        Map<String, Object> dataBackup = new HashMap<>();
        dataBackup.put("UPDATE_PRODUCT", map);
        PrincipalLogUtils.addOperationLog(ModuleNames.BIZ, ModuleNames.BIZ_PRODUCT, UserActions.UPDATE, "修改产品是否上下线为: " + isOnline, dataBackup);
        //产品下线备份数据
        Integer newId = null;
        if (!isOnline) {
            newId = backProductData(uid, isOnline);
        } else if (isOnline) {
            //产品上线判断产品下的所有服务是否为启用状态
            newId = isServicesOnlineInProduct(uid);
        }
        return newId;
    }

    /**
     * 产品上线时判断下属服务是否启用
     *
     * @param productUid
     */
    private Integer isServicesOnlineInProduct(String productUid) {
        Integer newId = null;
        Product product = (Product) dao.findForObject("ProductMapper.findActivedByUid", productUid);
        if (null != product) {
            newId = product.getId();
            List<ProductServiceRel> productServiceRelList = productServiceRelService.findByProductId(product.getId());
            if (null != productServiceRelList && productServiceRelList.size() > 0) {
                //判断产品下的每个服务状态是否启用状态
                List<String> notExistList = new ArrayList<>();
                List<String> notOnlineList = new ArrayList<>();
                for (ProductServiceRel productServiceRel : productServiceRelList) {
                    ServiceDto serviceDto = serviceService.findDtoActivedByUid(productServiceRel.getServiceUid());
                    if (!productServiceRel.getServiceProperty().getCode().equals(ProductServicePropertyEnum.OPTIONAL.getCode())) {
                        if (null != serviceDto) {
                            if (serviceDto.getStatus().compareTo(3) != 0 || serviceDto.getIsOnline() == null || !serviceDto.getIsOnline()) {
                                notOnlineList.add(serviceDto.getName());
                            }
                        } else {
                            notExistList.add(productServiceRel.getServiceName());
                        }
                    }
                }
                if (notExistList.size() > 0) {
                    //服务不存在异常
                    throw Exceptions.bizException(ErrorCodes.ERROR_PRODUCT_SERVICE_NOT_EXIST);
                }
                if (notOnlineList.size() > 0) {
                    //服务没有启用异常
                    throw Exceptions.bizException(ErrorCodes.ERROR_PRODUCT_SERVICE_NOT_ONLNE);
                }
            } else {
                //服务不存在
                throw Exceptions.bizException(ErrorCodes.ERROR_PRODUCT_SERVICE_NO_SERVICE);
            }
        } else {
            //产品异常
            throw Exceptions.bizException(ErrorCodes.ERROR_PRODUCT_NOT_EXIST);
        }
        return newId;
    }

    /**
     * 产品下线备份数据
     *
     * @param uid
     * @param isOnline
     * @throws ParseException
     */
    private Integer backProductData(String uid, boolean isOnline) throws ParseException {
        Product old = findActivedByUid(uid);
        Date date = dao.getDbDate();
        //将旧数据失效
        delete(uid, date);
        ProductDto productNew = new ProductDto();
        BeanUtils.copyProperties(old, productNew);
        productNew.setId(null);
        productNew.setActiveTime(date);
        productNew.setIsOnline(isOnline);
        if (isOnline) {
            productNew.setStatus(3);
        }
        super.save(productNew);
        copyServices(old.getId(), productNew.getId());
        copyRegion(old.getId(), productNew.getId());
        copyCargo(old.getId(), productNew.getId());
        return productNew.getId();
    }

    private void copyCargo(Integer oldId, Integer newId) {
        List<ProductCargotypeRel> productCargotypeRel = new ArrayList<>();
        List<ProductCargotypeRelDto> productCargotypeRelDtoList = productCargoTypeRelService.findByProductId(oldId);
        if (!CollectionUtils.isEmpty(productCargotypeRelDtoList)) {
            for (ProductCargotypeRelDto cargo : productCargotypeRelDtoList) {
                cargo.setProductId(newId);
                cargo.setId(null);
                ProductCargotypeRel productCargoTypeRel = new ProductCargotypeRel();
                BeanUtils.copyProperties(cargo, productCargoTypeRel);
                productCargotypeRel.add(productCargoTypeRel);
            }
            productCargoTypeRelService.batchsave(productCargotypeRel);
        }
        //productCargoTypeRelService.deleteByProductId(oldId);
    }

    private void copyRegion(Integer oldId, Integer newId) {
        List<ProductRegionRel> productRegionRelList = productRegionRelService.findByProductId(oldId);
        if (!CollectionUtils.isEmpty(productRegionRelList)) {
            for (ProductRegionRel region : productRegionRelList) {
                region.setProductId(newId);
                region.setId(null);
            }
            productRegionRelService.batchsave(productRegionRelList);
        }
        //productRegionRelService.deleteByProductId(oldId);
    }

    private void copyServices(int refId, int newId) {
        List<ProductServiceRel> serviceRels = productServiceRelService.findSimpleByProductId(refId);
        if (!CollectionUtils.isEmpty(serviceRels)) {
            for (ProductServiceRel servicerel : serviceRels) {
                Integer oldPsId = servicerel.getId();
                servicerel.setProductId(newId);
                servicerel.setId(null);
                productServiceRelService.save(servicerel);
                List<ProductServiceRegionRel> psRegions = productServiceRegionRelService.findRegionByPsId(oldPsId);
                if (!org.springframework.util.CollectionUtils.isEmpty(psRegions)) {
                    for (ProductServiceRegionRel psRegion : psRegions) {
                        psRegion.setPsId(servicerel.getId());
                        psRegion.setId(null);
                        productServiceRegionRelService.save(psRegion);
                    }
                }
                List<ProductServiceCargotypeRel> psCargos = productServiceCargotypeRelService.findCargosByPsId(oldPsId);
                if (!org.springframework.util.CollectionUtils.isEmpty(psCargos)) {
                    for (ProductServiceCargotypeRel psCargo : psCargos) {
                        psCargo.setPsId(servicerel.getId());
                        psCargo.setId(null);
                        productServiceCargotypeRelService.save(psCargo);
                    }
                }
                //productServiceRegionRelService.updatePsId(oldPsId, service.getId(), newId);
                //productServiceCargotypeRelService.updatePsId(oldPsId, service.getId());
            }
        }
        //productServiceRelService.deleteByProductId(refId);
    }

    /**
     * 过滤起点终点范围内的产品
     *
     * @param fcountryStr  fcountryStr
     * @param fprovinceStr fprovinceStr
     * @param fcityStr     fcityStr
     * @param fareaStr     fareaStr
     * @param fstreetStr   fstreetStr
     * @param fpostcode    fpostcode
     * @param tcountryStr  tcountryStr
     * @param tprovinceStr tprovinceStr
     * @param tcityStr     tcityStr
     * @param tareaStr     tareaStr
     * @param tstreetStr   tstreetStr
     * @param tpostcode    tpostcode
     * @return
     */
    @Override
    public List<Product> findByRegion(String fcountryStr, String fprovinceStr, String fcityStr, String fareaStr,
                                      String fstreetStr, String fpostcode,
                                      String tcountryStr, String tprovinceStr, String tcityStr, String tareaStr,
                                      String tstreetStr, String tpostcode) {
        Map<String, String> map = new HashMap<>();
        map.put("fcountryStr", fcountryStr);
        map.put("fprovinceStr", fprovinceStr);
        map.put("fcityStr", fcityStr);
        map.put("fareaStr", fareaStr);
        map.put("fstreetStr", fstreetStr);
        map.put("fpostcode", fpostcode);

        map.put("tcountryStr", tcountryStr);
        map.put("tprovinceStr", tprovinceStr);
        map.put("tcityStr", tcityStr);
        map.put("tareaStr", tareaStr);
        map.put("tstreetStr", tstreetStr);
        map.put("tpostcode", tpostcode);

        return dao.findForList("ProductMapper.findByRegion", map, Product.class);
    }


    /**
     * 根据产品的uid获取产品的范围信息
     *
     * @param productUid 产品的uid
     * @return 返回范围的信息
     */

    @Override
    public List<ProductAddressDto> getProductAddress(String productUid) {
        List<ProductAddressDto> productAddressDtoList = new ArrayList<>();
        //1、得到产品-分区表的信息
        Product product = this.findShortActivedByUid(productUid);
        List<ProductRegionRel> productRegionRelList = productRegionRelService.findByProductId(product.getId());
        //处理分区方案没有配制的情况
        if (CollectionUtils.isEmpty(productRegionRelList)) {
            ProductAddressDto productAddressDto = new ProductAddressDto();
            productAddressDto.setAddressType(CommCodes.PRODUCT_SERVICE_REGION_START);
            productAddressDtoList.add(productAddressDto);

            productAddressDto = new ProductAddressDto();
            productAddressDto.setAddressType(CommCodes.PRODUCT_SERVICE_REGION_END);
            productAddressDtoList.add(productAddressDto);


        }
        //处理分区方案只配置一种的情况
        if (!CollectionUtils.isEmpty(productRegionRelList) && productRegionRelList.size() == 1) {
            ProductRegionRel productRegionRel = productRegionRelList.get(0);
            ProductAddressDto productAddressDto;
            if (CommCodes.PRODUCT_SERVICE_REGION_START.equals(productRegionRel.getType())) {
                productAddressDto = new ProductAddressDto();
                productAddressDto.setAddressType(CommCodes.PRODUCT_SERVICE_REGION_END);
                productAddressDtoList.add(productAddressDto);
            } else if (CommCodes.PRODUCT_SERVICE_REGION_END.equals(productRegionRel.getType())) {
                productAddressDto = new ProductAddressDto();
                productAddressDto.setAddressType(CommCodes.PRODUCT_SERVICE_REGION_START);
                productAddressDtoList.add(productAddressDto);
            }
        }

        //2、得到产品的地址范围,并放到集合中
        for (ProductRegionRel productRegionRel : productRegionRelList) {
            List<RegionItem> regionItemList = regionService.findItemBySchemaUid(productRegionRel.getSchemaUid());
            for (RegionItem regionItem : regionItemList) {
                ProductAddressDto productAddressDto = this.getProductAddressDto(productRegionRel.getType(), regionItem);
                productAddressDtoList.add(productAddressDto);
            }
        }

        //3、得到揽收地址范围，并放到集合中去
        List<ProductServiceRel> productServiceRelList = productServiceRelService.findByProductId(product.getId());


        int pickUpServiceCount = 0;
        int pickUpRegionCount = 0;
        List<ProductAddressDto> pickUpAddressList = new ArrayList<>();
        for (ProductServiceRel productServiceRel : productServiceRelList) {
            if (TopServiceTypes.RECEIVE.equals(productServiceRel.getServiceTypeCode())) {
                pickUpServiceCount = pickUpServiceCount + 1;
                com.sz.biz.logistics.core.entity.Service service = serviceService.findActivedByUid(productServiceRel.getServiceUid());
                List<ServiceRegionRel> serviceRegionRelList = serviceRegionRelService.findByServiceId(service.getId());
                for (ServiceRegionRel serviceRegionRel : serviceRegionRelList) {
                    if (serviceRegionRel.getType().equals(CommCodes.PRODUCT_SERVICE_REGION_START)) {
                        pickUpRegionCount = pickUpRegionCount + 1;
                    }
                    List<RegionItem> regionItemList = regionService.findItemBySchemaUid(serviceRegionRel.getSchemaUid());
                    for (RegionItem regionItem : regionItemList) {
                        if (serviceRegionRel.getType().equals(CommCodes.PRODUCT_SERVICE_REGION_START)) {//揽收只有配置为s的才进行取揽收地址
                            String addressType = CommCodes.PRODUCT_SERVICE_REGION_PICKUP;//揽收
                            ProductAddressDto productAddressDto = this.getProductAddressDto(addressType, regionItem);
                            pickUpAddressList.add(productAddressDto);
                        }
                    }
                }
            }
        }

        //如果揽收的服务个数与揽收分区的服务个数不一样，那么认为有的服务没有范围，所以配置所有揽收地址都可用。
        if (pickUpServiceCount != pickUpRegionCount) {
            ProductAddressDto productAddressDto = new ProductAddressDto();
            productAddressDto.setAddressType(CommCodes.PRODUCT_SERVICE_REGION_PICKUP);
            productAddressDtoList.add(productAddressDto);
        } else {
            productAddressDtoList.addAll(pickUpAddressList);
        }
        return productAddressDtoList;
    }

    /**
     * 根据指定类型获取相应类型的地址集合信息，并返回，如果未指定获取所有的信息返回
     *
     * @param productUid
     * @param addressType public final static String PRODUCT_SERVICE_REGION_START = "s";
     *                    public final static String PRODUCT_SERVICE_REGION_END = "e";
     *                    public final static String PRODUCT_SERVICE_REGION_PICKUP = "l";
     * @return 根据指定类型获取相应类型的地址集合信息，并返回，如果未指定获取所有的信息返回
     */
    @Override
    public List<ProductAddressDto> getProductAddress(String productUid, String addressType) {
        List<ProductAddressDto> allAddressDtoList = this.getProductAddress(productUid);
        List<ProductAddressDto> addressDtoList = new ArrayList<>();
        for (ProductAddressDto productAddressDto : allAddressDtoList) {
            if (addressType.equals(productAddressDto.getAddressType())) {
                addressDtoList.add(productAddressDto);
            }
        }
        return addressDtoList;
    }

    /**
     * 根据指定的地址集合信息，判断指定的地址信息是否满足要求，如果满足，那么返回true，否则false
     *
     * @param productAddressDtoList 地址的集合信息
     * @param addressDto            要判断的地址信息
     * @return 如果满足，那么返回true，否则false
     */
    @Override
    public boolean checkProductAddress(List<ProductAddressDto> productAddressDtoList, ProductAddressDto addressDto) {
        for (ProductAddressDto productAddressDto : productAddressDtoList) {
            String itemDetail = addressDto.getItemDetail();
            if (StringUtils.isEmpty(itemDetail)) {
                addressDto.setItemDetail();
                itemDetail = addressDto.getItemDetail();
            }
            String[] addressDetail = itemDetail.split("/");
            for (int i = 0; i < addressDetail.length; i++) {
                if (itemDetail.equals(productAddressDto.getItemDetail()) || StringUtils.isEmpty(productAddressDto.getCountry())) {//当国家为空时，代表的是所有的地址都适用
                    return true;
                } else if (itemDetail.contains("/")) {
                    itemDetail = itemDetail.substring(0, itemDetail.lastIndexOf("/"));
                }
            }
        }
        return false;


    }

    /**
     * 把分区regionItem转成productAddressDto信息
     *
     * @param addressType s/e/l
     * @param regionItem
     * @return
     */
    private ProductAddressDto getProductAddressDto(String addressType, RegionItem regionItem) {
        String strItemDetail = regionItem.getItemDetail();
        String[] itemDetail = strItemDetail.split("_");

        String strAddress = itemDetail[0];
        String[] address = new String[5];
        String[] add = strAddress.split("/");
        for (int i = 0; i < add.length; i++) {
            address[i] = add[i];
        }
        ProductAddressDto productAddressDto = new ProductAddressDto();
        if (itemDetail.length == 2) {
            productAddressDto.setItemDetail(itemDetail[0]);
            productAddressDto.setStrItemDetail(itemDetail[1]);
        }

        productAddressDto.setAddressType(addressType);
        productAddressDto.setCountry(address[0]);

        if (LanguageCode.CN_UPPER.equals(regionItem.getCountry())) {
            productAddressDto.setProvince(address[1]);
            productAddressDto.setCity(address[2]);
            if (CommCodes.REGION_SEA_ADDRESS_TYPE == regionItem.getType() || CommCodes.REGION_AIR_ADDRESS_TYPE == regionItem.getType()) {
                productAddressDto.setTransportType(regionItem.getType() == CommCodes.REGION_SEA_ADDRESS_TYPE ? CommCodes.TRANSPORT_SEA : CommCodes.TRANSPORT_AIR);
                productAddressDto.setTransportId(regionItem.getTransportId());
            } else {
                productAddressDto.setArea(address[3]);
                productAddressDto.setStreet(address[4]);
            }
        } else {
            productAddressDto.setCity(address[1]);
            if (CommCodes.REGION_SEA_ADDRESS_TYPE == regionItem.getType() || CommCodes.REGION_AIR_ADDRESS_TYPE == regionItem.getType()) {
                productAddressDto.setTransportType(regionItem.getType() == CommCodes.REGION_SEA_ADDRESS_TYPE ? CommCodes.TRANSPORT_SEA : CommCodes.TRANSPORT_AIR);
                productAddressDto.setTransportId(regionItem.getTransportId());
            }
        }


        productAddressDto.setEnable(true);
        return productAddressDto;
    }

    /**
     * 根据客户id检查范围
     *
     * @param uid
     * @param customerId
     * @param transportType public static final int TRANSPORT_SEA = 1;//海运地址
     *                      public static final int TRANSPORT_AIR = 6;//空运地址
     *                      public static final int TRANSPORT_LAND = 11;//陆运地址
     * @return
     */
    @Override
    public ResultDto checkRegionByCustomerId(String uid, Integer customerId, int transportType) {
        Map<Integer, Boolean> map = new HashMap<>();
        //判断发件人地址是否可用
        List<ProductAddressDto> addressDtoList = this.getProductAddress(uid, CommCodes.PRODUCT_SERVICE_REGION_START);
        List<CusUserAddressDto> cusUserAddressDtoList = customerUserAddressService.queryByCusIdAndIdsAndType(0, customerId, 1, transportType);
        for (CusUserAddressDto addressDto : cusUserAddressDtoList) {
            ProductAddressDto productAddressDto = getProductAddressDto(transportType, addressDto);
            boolean bOk = this.checkProductAddress(addressDtoList, productAddressDto);
            map.put(addressDto.getId(), bOk);
        }

        //判断收件人地址是否可用
        addressDtoList = this.getProductAddress(uid, CommCodes.PRODUCT_SERVICE_REGION_END);
        cusUserAddressDtoList = customerUserAddressService.queryByCusIdAndIdsAndType(0, customerId, 2, transportType);
        for (CusUserAddressDto start : cusUserAddressDtoList) {
            ProductAddressDto productAddressDto = getProductAddressDto(transportType, start);
            boolean bOk = this.checkProductAddress(addressDtoList, productAddressDto);
            map.put(start.getId(), bOk);
        }
        //判断揽收地址是否可用
        addressDtoList = this.getProductAddress(uid, CommCodes.PRODUCT_SERVICE_REGION_PICKUP);
        cusUserAddressDtoList = customerUserAddressService.queryByCusIdAndIdsAndType(0, customerId, 3, 0);
        for (CusUserAddressDto start : cusUserAddressDtoList) {
            ProductAddressDto productAddressDto = getProductAddressDto(transportType, start);
            boolean bOk = this.checkProductAddress(addressDtoList, productAddressDto);
            map.put(start.getId(), bOk);
        }
        return new ResultDto(map);
    }

    /**
     * 把指定的对象userAddressDto转换成对象ProductAddressDto
     *
     * @param transportType  public final static String PRODUCT_SERVICE_REGION_START = "s";
     *                       public final static String PRODUCT_SERVICE_REGION_END = "e";
     *                       public final static String PRODUCT_SERVICE_REGION_PICKUP = "l";
     * @param userAddressDto 用户的地址dto
     * @return
     */
    @Override
    public ProductAddressDto getProductAddressDto(int transportType, CusUserAddressDto userAddressDto) {
        ProductAddressDto productAddressDto = new ProductAddressDto();
        productAddressDto.setCountry(userAddressDto.getCountryCode());
        productAddressDto.setProvince(userAddressDto.getProvinceId());
        productAddressDto.setCity(userAddressDto.getCityId());
        productAddressDto.setArea(userAddressDto.getDistrictId());
        productAddressDto.setStreet(userAddressDto.getStreetId());
        productAddressDto.setTransportId(userAddressDto.getTransportId());
        productAddressDto.setTransportType(transportType);
        if (userAddressDto.getType() == AddressTypeEnum.SENDADDRESS.getCode()) {
            productAddressDto.setAddressType(CommCodes.PRODUCT_SERVICE_REGION_START);
        } else if (userAddressDto.getType() == AddressTypeEnum.RECEIVERADDRESS.getCode()) {
            productAddressDto.setAddressType(CommCodes.PRODUCT_SERVICE_REGION_END);
        } else if (userAddressDto.getType() == AddressTypeEnum.PICKADDRESS.getCode()) {
            productAddressDto.setAddressType(CommCodes.PRODUCT_SERVICE_REGION_PICKUP);
        }
        return productAddressDto;
    }

    @Override
    public int getProductAcceptType(String productUid) {
        int acceptType = CommCodes.PRODUCT_ACCETP_TYPE_AUTO;
        if (!StringUtils.isEmpty(productUid)) {
            Product product = this.findShortActivedByUid(productUid);
            acceptType = product.getAcceptType();
        }
        return acceptType;
    }

    private String getCountryPreCode(String countryCode) {
        return "CN".equals(countryCode) ? "2" : "3";
    }

    @Autowired
    protected I18nMessages messageSource;

    @Override
    public ResultDto checkWeight(String uid, WeightDto weightDto) {
        Product product = (Product) dao.findForObject("ProductMapper.findActivedByUid", uid);
        if (product.getWeightLimitMin() == null && product.getWeightLimitMax() == null) {
            return new ResultDto(true);
        }
        BigDecimal targetWeight = unitConversionService.getTargetWeight(
                weightDto.getWeight(), weightDto.getWeightUnitCode(), product.getWeightLimitUnitCode());
        if ((product.getWeightLimitMin() != null && product.getWeightLimitMin().compareTo(targetWeight) > 0) ||
                (product.getWeightLimitMax() != null && product.getWeightLimitMax().compareTo(targetWeight) < 0)) {

            String msg = messageSource.getMessage(ErrorCodes.ERROR_PRODUCT_WEIGHT_LIMIT.getMessageKey(),
                    new String[]{product.getWeightLimitMin().doubleValue() + "",
                            product.getWeightLimitMax().doubleValue() + "", product.getWeightLimitUnitCode()});
            ResultDto dto = new ResultDto(false);
            dto.setMsg(msg);
            return dto;
        }
        return new ResultDto(true);
    }

    @Override
    public List<ProductRegionRel> getRegionByProductId(Integer id) {
        List<ProductRegionRel> regionList = productRegionRelService.findByProductId(id);
        return regionList;
    }

    @Override
    public ResultDto getWeightByProductId(Integer id) {
        ResultDto dto = new ResultDto();
        Map map = (Map) dao.findForObject("ProductMapper.findByWeightByProductId", id);
        dto.setData(map);
        return dto;
    }

    /**
     * 根据uid查询产品的揽收服务的信息
     *
     * @param uid uid
     * @return ProductReceiveInfoDto
     */
    @Override
    public ProductReceiveInfoDto findProductReceiveInfoByUid(String uid) {
        List<ProductServiceRel> list = findProductServices(uid, "ALL", null, false, true);
        ProductReceiveInfoDto dto = new ProductReceiveInfoDto();
        dto.setUid(uid);
        if (!CollectionUtils.isEmpty(list)) {
            list.forEach(productServiceRelDto -> {
                String code = productServiceRelDto.getServiceProperty().getCode();
                if (code.equals(ProductServicePropertyEnum.REQUIRED.getCode()) || code.equals(ProductServicePropertyEnum.MAIN.getCode())) {
                    if (SERVICE_TYPE_RECEIVE.equals(productServiceRelDto.getServiceTypeCode())) {
                        dto.setProductReceive(true);
                    }
                } else {
                    if (SERVICE_TYPE_RECEIVE.equals(productServiceRelDto.getServiceTypeCode())) {
                        ServiceTypeReceiveInfo info = new ServiceTypeReceiveInfo();
                        info.setServiceReceive(true);
                        info.setServiceTypeCode(productServiceRelDto.getServiceTypeCode());
                        info.setServiceTypeName(productServiceRelDto.getServiceTypeName());
                        if (!dto.getServiceTypeReceiveInfo().contains(info)) {
                            dto.getServiceTypeReceiveInfo().add(info);
                        }
                    }
                }
            });
        }
        return dto;
    }


    /**
     * 根据产品id,countryCode和type查询机场或港口，支持分页
     * 用于下单时，添加地址，选择国家、城市、港口/机场
     * @param id            --产品Id
     * @param countryCode   --国家编码
     * @param cityId        --城市Id
     * @param type          --字母区分的起点或重点类型：s-起点；e-终点
     * @param q             --搜索关键字
     * @param pageIndex     --分页
     * @param pageSize      --页面大小
     * @return
     */
    @Override
    public ResultDto getTransportByProductIdAndType(Integer id, String countryCode, String cityId, String type, String q, int pageIndex, int pageSize) {
        if (StringUtils.isEmpty(countryCode)) { // IllegalArgument
            return new ResultDto();
        }
        ResultDto dto;

        ProductRegionRel productRegionRel = productRegionRelService.getProductRegion(id, type);
        if (productRegionRel != null) { //已经设置了产品范围
            String schemaUid = productRegionRel.getSchemaUid();
            dto = regionSchemaService.findTransportByUid(schemaUid, countryCode, cityId, pageIndex, pageSize, id, q);
        } else { //未设置产品范围
            // 获取地址类型是港口还是机场，从产品中取得产品组的类型
            int addressType = this.getAddressType(id);
            dto = regionItemService.findAirByRegionIds(null, countryCode, cityId, q, pageIndex, pageSize, addressType);
        }
        return dto;
    }
    private int getAddressType(Integer productId) {
        ProductGroup productGroup = this.judgeProductGroup(productId);
        int parentId = productGroup.getParentId();
        if (parentId != ProductGroupCode.SEA_TRANSPORT  && parentId != ProductGroupCode.AIR_TRANSPORT ) {
            parentId =  ProductGroupCode.LAND_TRANSPORT;//如果产品组的一级非海运与空运，那么设置其为速递地址
        }
        int addressType = parentId;
        return addressType;
    }

    private ProductGroup judgeProductGroup(Integer productId) {
        Product product = this.findShortActivedById(productId);
        if (ObjectUtils.isEmpty(product)) {
            throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "产品未找到！");
        }

        Integer leafId = product.getProductGroupLeafId();
        if (leafId != null && leafId <= 0) {
            throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "产品的产品组未配置！");
        }

        ProductGroup productGroup = productGroupService.findById(leafId);
        if (ObjectUtils.isEmpty(productGroup)) {
            throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "产品组未找到！");
        }
        return productGroup;
    }

    /**
     * 根据产品id,type,countryCode和parentId查询地区
     *
     * @param id
     * @param countryCode
     * @param parentId
     * @param type
     * @return
     */
    @Override

    public ResultDto getAreaByProductIdAndType(Integer id, String countryCode, String parentId, String type, String q, int pageIndex, int pageSize) {
        ResultDto dto = null;
        if (!CommCodes.PRODUCT_SERVICE_REGION_PICKUP.equals(type)) {//非揽收地址查询(包括收件地址和发件地址)
            ProductRegionRel productRegionRel = productRegionRelService.getProductRegion(id, type);

            List<String> schemaUids = new ArrayList<>();
            if (productRegionRel != null) {
                if (productRegionRel.getSchemaUid() != null) {
                    schemaUids.add(productRegionRel.getSchemaUid());
                }
            }
            dto = regionSchemaService.findCountryAreaByUid(schemaUids, countryCode, parentId, q, pageIndex, pageSize);


        } else {//揽收地址查询
            List<String> regionSchemaList = getServiceRegionSchema(id);
            dto = regionSchemaService.findCountryAreaByUid(regionSchemaList, countryCode, parentId, q, pageIndex, pageSize);
        }
        return dto;
    }

    /**
     * 查询揽收服务范围的分区方案UID集合
     *
     * @param id
     * @return
     */
    private List<String> getServiceRegionSchema(Integer id) {
        List<String> regionSchemaList = new ArrayList<>();
        //根据产品id查询所有的服务
        List<ProductServiceRel> services = productServiceRelService.findByProdIdAndServiceProperty(id, null);
        if (services != null) {
            for (ProductServiceRel productServiceRel : services) {
                //判断是否为揽收服务
                if (SERVICE_TYPE_RECEIVE.equals(productServiceRel.getServiceTypeCode())) {
                    //根据服务的UID查询服务详情
                    ServiceDto serviceDto = serviceService.findDtoActivedByUid(productServiceRel.getServiceUid());
                    //根据服务id查询服务和分区方案的关系
                    List<ServiceRegionRel> serviceRegionRelList = serviceRegionRelService.findByServiceId(serviceDto.getId());
                    if (!CollectionUtils.isEmpty(serviceRegionRelList)) {
                        for (ServiceRegionRel serviceRegionRel : serviceRegionRelList) {
                            //将符合揽收服务范围的分区方案SchemaUid放进集合
                            if (CommCodes.PRODUCT_SERVICE_REGION_START.equals(serviceRegionRel.getType())) {
                                List<RegionItem> regionItemList = regionService.findItemBySchemaUid(serviceRegionRel.getSchemaUid());
                                if (CollectionUtils.isEmpty(regionItemList)) {
                                    regionSchemaList.clear();
                                    return regionSchemaList;
                                }
                                regionSchemaList.add(serviceRegionRel.getSchemaUid());
                            }
                        }
                    } else {
                        regionSchemaList.clear();
                        return regionSchemaList;
                    }
                }
            }
        }
        return regionSchemaList;
    }

    /**
     * 获取排除产品已有服务类型的其他服务类型
     *
     * @param productId
     * @return
     */
    @Override
    public List<SysDict> findServiceTypesExcludePrd(Integer productId) {
        ParamData pd = new ParamData();
        pd.put("productId", productId);
        pd.put("catalog", "biz.service.type");
        pd.put("language", PrincipalUtils.getLocalLanguage());/*获取当前的语言*/
        List<SysDict> dictList = dao.findForList(getSqlName("findServiceTypesExcludePrd"), pd, SysDict.class);
        SysDict tp = new SysDict();
        tp.setId(-1);
        if (LanguageCode.ZH_CN.equals(PrincipalUtils.getLocalLanguage().toLowerCase()) ||
                LanguageCode.ZH_TW.equals(PrincipalUtils.getLocalLanguage().toLowerCase()) ||
                LanguageCode.ZH_HK.equals(PrincipalUtils.getLocalLanguage().toLowerCase())) {
            tp.setName("全部");
        } else {
            tp.setName("All");
        }
        tp.setCode("-1");
        dictList.add(0, tp);
        return dictList;
    }

    @Override
    protected String getMapperNamespace() {
        return "ProductMapper";
    }


    /**
     * 根据产品id和type查询服务范围的所有国家
     *
     * @param id
     * @param type
     * @param q
     * @param pageIndex
     * @param pageSize  @return
     */
    @Override
    public ResultDto getCountryByProductIdAndType(Integer id, String type, String q, int pageIndex, int pageSize) {
        ResultDto dto = null;
        if (!CommCodes.PRODUCT_SERVICE_REGION_PICKUP.equals(type)) {//非揽收地址查询(包括收件地址和发件地址)
            List<String> schemaUidList = new ArrayList<>();
            ProductRegionRel productRegionRel = productRegionRelService.getProductRegion(id, type);
            if (productRegionRel != null) {
                schemaUidList.add(productRegionRel.getSchemaUid());
            }
            //无论schemaUidList是否有值都应去查询，因为有的产品没有配置分区
            dto = regionSchemaService.findRegionCountryByUid(schemaUidList, q, pageIndex, pageSize);

        } else {/*揽收地址查询*/
            List<String> schemaUidList = this.getServiceRegionSchema(id);
            dto = regionSchemaService.findRegionCountryByUid(schemaUidList, q, pageIndex, pageSize);
        }
        return dto;
    }

    /**
     * 产品组信息、产品可选服务信息
     *
     * @param id
     * @return
     */
    @Override
    public ProductGroupOptServiceInfo getProductServiceInfos(Integer id) {
        ProductGroupOptServiceInfo productGroupOptServiceInfo = new ProductGroupOptServiceInfo();
        //产品组信息
        ProductGroupInfo productGroupInfo = getProductGroupById(id);
        productGroupOptServiceInfo.setProductGroupInfo(productGroupInfo);
        //产品主服务和必选服务是否包含揽收服务
        productGroupOptServiceInfo.setProductReceive(true);
        List<String> receiveServiceUids = productServiceRelService.checkMainRequiredService(id, SERVICE_TYPE_RECEIVE);
        if (CollectionUtils.isEmpty(receiveServiceUids)) {
            productGroupOptServiceInfo.setProductReceive(false);
        }
        //产品可选服务列表-服务类型编码+服务类型名称
        List<Map> optionalServiceTypes = productServiceRelService.findOptionalServiceTypes(id);
        productGroupOptServiceInfo.setOptionalServiceTypes(optionalServiceTypes);
        return productGroupOptServiceInfo;
    }

    /**
     * 使用产品的id获取产品的基本信息
     *
     * @param productId
     * @return
     */
    @Override
    public Product findShortById(Integer productId) {
        return (Product) dao.findForObject("ProductMapper.findById", productId);
    }

    /**
     * 获取当前已启用的所有产品
     */
    @Override
    public List<Product> findAllOnlineProduct() {
        return dao.findForList("ProductMapper.findAllOnlineProduct", Product.class);
    }

    @Override
    public ProductGroup findGroupByUid(String productUid) {
        ProductGroup productGroup = null;
        Product product = this.findShortActivedByUid(productUid);
        if (!ObjectUtils.isEmpty(product)) {
            int leftId = product.getProductGroupLeafId();
            productGroup = productGroupService.findById(leftId);
        }
        return productGroup;
    }

    @Override
    public String findProductCurrencyCodeByUid(String productUid) {
        String currencyCode = null;
        ProductGroup productGroup = this.findGroupByUid(productUid);
        if (!ObjectUtils.isEmpty(productGroup)) {
            currencyCode = productGroup.getCurrencyCode();
        }
        return currencyCode;
    }
}
